/**
 * This program is free software but WITHOUT ANY WARRANTY OR CONDITIONS OF ANY KIND.
 *
 * Copyright (C) 2008-2013 www.pretty-tools.com
 */

/**
 * Image Resolver.
 *
 * @author Alexander Kozlov
 */
function wsshImageResolver()
{
    this.logger = yrprxFactory.createLogger("wsshImageResolver");

    this._items = null;
    this.rulesObserver = null;

    this.linkRegExp = new RegExp("\\.(jpg|jpeg|png|bmp|tif|tiff)$", "i")
}

wsshImageResolver.prototype.getItems = function()
{
    if (!this._items)
        this.loadRules();

    return this._items;
}

wsshImageResolver.prototype.getItem = function(i)
{
    return this.getItems()[i];
}

wsshImageResolver.prototype.loadRules = function()
{
    try
    {
        var userProfile = wsshWebProfileSerializer.loadUserProfile();
        var predefinedProfile = wsshWebProfileSerializer.loadPredefinedProfile();
        if (!userProfile.length)
            this._items = predefinedProfile;
        else
            this._items = userProfile.concat(predefinedProfile);

        if (wsshConfig.useSubscriptions)
        {
            var subscriptions = wsshSubscriptionSerializer.load();
            for (var s in subscriptions)
            {
                var profile = wsshWebProfileSerializer.loadProfile(subscriptions[s].name);
                if (profile.length) this._items = this._items.concat(profile);
            }
        }

        if (this.logger.enabled) this.logger.debug("loadRules: loaded items: " + this._items.length);
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("loadRules: ", ex);
        this._items = [];
    }
}

wsshImageResolver.prototype.init = function()
{
    this.loadRules();
    this.initRulesObserver();
}

wsshImageResolver.prototype.destroy = function()
{
    try
    {
        this.logger.debug("destroy: remove rule observer");

        yrprxObserverServiceHelper.removeObserver(this.rulesObserver, WEBSLIDESHOW_UPDATE_RULES_EVENT);
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("destroy: ", ex);
    }
}

wsshImageResolver.prototype.initRulesObserver = function()
{
    try
    {
        this.logger.debug("initRulesObserver: add rule observer");

        var resolver = this;

        this.rulesObserver = {
            observe: function(subject, topic, data) {
                resolver.onRulesUpdated();
            }
        };

        // subscribe
        yrprxObserverServiceHelper.addObserver(this.rulesObserver, WEBSLIDESHOW_UPDATE_RULES_EVENT);
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("initRulesObserver: ", ex);
    }
}

wsshImageResolver.prototype.onRulesUpdated = function()
{
    this._items = null;
}

wsshImageResolver.prototype.isDirectImageLink = function(url)
{
    return url && url.indexOf("?") == -1 && url.match(this.linkRegExp); // it's direct link to image
}

wsshImageResolver.prototype.isParentALink = function(elem)
{
    var parent = elem.parentNode;
    if (!parent)
        return false;

    return parent.tagName.toUpperCase() == "A";
}

wsshImageResolver.prototype.isParentDirectImageLink = function(elem)
{
    var parent = elem.parentNode;
    if (!parent)
        return false;

    return parent.tagName.toUpperCase() == "A" // parent is link
            && this.isDirectImageLink(parent.href); // it's direct link to image
}

wsshImageResolver.prototype.getImageURL = function(doc, img, docURL)
{
    if (!doc || !img)
        return null;

    try
    {
        if (!docURL)
            docURL = doc.location.href;

        for (var i = 0, count = this.getItems().length; i < count; ++i)
        {
            var item = this.getItem(i);
            if (docURL.indexOf(item.domain) == -1)
                continue;

            for (var p = 0; p < item.pages.length; ++p)
            {
                var page = item.pages[p];

                if (page.disabled || !page.supported)
                    continue;

                if (!docURL.match(page.pattern))
                    continue;

                var elem = img;
                if (page.elementTag != "IMG")
                {
                    if (!img.parentNode || img.parentNode.tagName.toUpperCase() != page.elementTag)
                        continue;

                    elem = img.parentNode;
                }

                var url = page.extractUrl(elem);
                if (!url || page.elementPattern && !url.match(page.elementPattern))
                    continue;

                return !page.elementTemplate ? url : page.createURLFromTemplate(url);
            }
        }

        this.logger.debug("getImageURL: No predefined template...");

        if (this.isParentDirectImageLink(img))
            return img.parentNode.href;
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("getImageURL: ", ex);
    }
    return img.src;
}

/**
 * Special getImageURL() for Google Chrome
 */
wsshImageResolver.prototype.resolveImageURL = function(imageSrcUrl, linkUrl, docURL)
{
    if (!imageSrcUrl || !docURL)
        return null;

    try
    {
        for (var i = 0, count = this.getItems().length; i < count; ++i)
        {
            var item = this.getItem(i);
            if (docURL.indexOf(item.domain) == -1)
                continue;

            for (var p = 0; p < item.pages.length; ++p)
            {
                var page = item.pages[p];

                if (page.disabled || !page.supported)
                    continue;

                if (!docURL.match(page.pattern))
                    continue;

                var url = null;
                if (page.elementTag == "IMG")
                    url = imageSrcUrl;
                else if (page.elementTag == "A" || page.elementTag == "AREA")
                    url = linkUrl;

                if (!url || page.elementPattern && !url.match(page.elementPattern))
                    continue;

                return !page.elementTemplate ? url : page.createURLFromTemplate(url);
            }
        }

        this.logger.debug("resolveImageURL: No predefined template...");
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("resolveImageURL: ", ex);
    }

    if (this.isDirectImageLink(linkUrl))
        return linkUrl;

    return imageSrcUrl;
}

wsshImageResolver.prototype.getImages = function(doc, onlyCountImages, docURL)
{
    try
    {
        if (!docURL)
            docURL = doc.location.href;

        if (this.logger.enabled) this.logger.debug("getImages: looking for : " + docURL);

        for (var i = 0, count = this.getItems().length; i < count; ++i)
        {
            var item = this.getItem(i);

            if (docURL.indexOf(item.domain) == -1)
                continue;

            if (this.logger.enabled) this.logger.debug("getImages: domain matches to : " + item.domain);

            for (var p = 0; p < item.pages.length; ++p)
            {
                var page = item.pages[p];

                if (page.disabled || !page.supported)
                    continue;

                if (!docURL.match(page.pattern))
                    continue;

                if (this.logger.enabled) this.logger.debug("getImages: page matches to : " + page.pattern +" tag : " + page.elementTag + " elem filter: " + page.elementPattern);

                if (!onlyCountImages)
                {
                    var images = yrprxHTMLContentHelper.getAllElementsByTagName(doc, page.elementTag, function(elem) {
                        var url = page.extractUrl(elem);
                        if (!url) // check URL
                            return null;

                        if (page.elementPattern && !url.match(page.elementPattern))
                            return null;

                        if (page.elementTemplate) // build url from template
                            url = page.createURLFromTemplate(url);

                        return url;
                    });

                    if (images.length)
                        return this.removeDuplicates(images);
                }
                else
                {
                    var count = 0;
                    yrprxHTMLContentHelper.enumerateElementsByTagName(doc, page.elementTag, function(elem) {
                        var url = page.extractUrl(elem);
                        if (!url || (page.elementPattern && !url.match(page.elementPattern)))
                            return;

                        count++;
                    });

                    if (count > 0)
                        return count;
                }
            }
        }

        this.logger.debug("getImages: No predefined template. Looking for images...");

        // search for images or direct links

        var minWidth = wsshConfig.minImageWidth, minHeight = wsshConfig.minImageHeight, resolver = this;

        if (!onlyCountImages)
        {
            var result = yrprxHTMLContentHelper.getAllElementsByTagName(doc, "img", function(elem) {
                // check parent
                if (resolver.isParentDirectImageLink(elem))
                    return elem.parentNode.href;

                var naturalSize = yrprxBrowser.getNaturalSize(elem);
                // check width
                if (typeof naturalSize.width != "undefined" && typeof naturalSize.height != "undefined"
                        && (naturalSize.width > 0 && naturalSize.width < minWidth || naturalSize.height > 0 && naturalSize.height < minHeight))
                    return null;

                return elem.src;
            });

            // There are no apropriate images... Look for direct links....
            if (!result || !result.length)
            {
                this.logger.debug("getImages: There are no appropriate images. Looking for direct links...");

                result = yrprxHTMLContentHelper.getAllElementsByTagName(doc, "a", function(elem) {
                    return resolver.isDirectImageLink(elem.href) ? elem.href : null;
                });
            }

            if (this.logger.enabled)
            {
                if (!result || !result.length) // still nothing :-(
                    this.logger.debug("getImages: There are no appropriate images or links...");
                else
                    this.logger.debug("getImages: There are " + result.length + " appropriate images.");
            }

            return this.removeDuplicates(result);
        }
        else
        {
            var countImages = 0;

            yrprxHTMLContentHelper.enumerateElementsByTagName(doc, "img", function(elem) {
                // check width
                if (!resolver.isParentDirectImageLink(elem))
                {
                    var naturalSize = yrprxBrowser.getNaturalSize(elem);
                    if (typeof naturalSize.width != "undefined" && typeof naturalSize.height != "undefined"
                            && (naturalSize.width > 0 && naturalSize.width < minWidth || naturalSize.height > 0 && naturalSize.height < minHeight))
                        return;
                }

                countImages++;
            });

            // There are no apropriate images... Look for direct links....
            if (!countImages)
            {
                this.logger.debug("getImages: There are no appropriate images. Looking for direct links...");

                yrprxHTMLContentHelper.enumerateElementsByTagName(doc, "a", function(elem) {
                    if (resolver.isDirectImageLink(elem.href))
                        countImages++;
                });
            }

            if (this.logger.enabled)
            {
                if (!countImages) // still nothing :-(
                    this.logger.debug("getImages: There are no appropriate images or links...");
                else
                    this.logger.debug("getImages: There are " + countImages + " appropriate images.");
            }

            return countImages;
        }
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("getImages: ", ex);
    }
    return !onlyCountImages ? new Array() : 0;
}

wsshImageResolver.prototype.getSatisfiedElements = function(doc, docURL)
{
    try
    {
        if (!docURL)
            docURL = doc.location.href;

        if (this.logger.enabled) this.logger.debug("getSatisfiedElements: looking for : " + docURL);

        for (var i = 0, count = this.getItems().length; i < count; ++i)
        {
            var item = this.getItem(i);

            if (docURL.indexOf(item.domain) == -1)
                continue;

            if (this.logger.enabled) this.logger.debug("getSatisfiedElements: domain matches to : " + item.domain);

            for (var p = 0; p < item.pages.length; ++p)
            {
                var page = item.pages[p];

                if (page.disabled || !page.supported)
                    continue;

                if (!docURL.match(page.pattern))
                    continue;

                if (this.logger.enabled) this.logger.debug("getSatisfiedElements: page matches to : " + page.pattern +" tag : " + page.elementTag + " elem filter: " + page.elementPattern);

                var images = yrprxHTMLContentHelper.getAllElementsByTagName(doc, page.elementTag, function(elem) {
                    var url = page.extractUrl(elem);
                    if (!url) // check URL
                        return null;

                    if (page.elementPattern && !url.match(page.elementPattern))
                        return null;

                    if (page.elementTemplate) // build url from template
                        url = page.createURLFromTemplate(url);

                    return { url: url, elem: elem };
                });

                if (images.length)
                    return images;
            }
        }

        this.logger.debug("getSatisfiedElements: No predefined template. Nothing to do...");
    }
    catch(ex)
    {
        if (this.logger.enabled) this.logger.error("getSatisfiedElements: ", ex);
    }
    return new Array();
}

wsshImageResolver.prototype.removeDuplicates = function(images, destination)
{
    if (!images || !images.length)
        return images;

    var result = !destination ? new Array() : destination;

    var found;
    for (var i = 0, count = images.length; i < count; ++i)
    {
        found = false;
        for (var j = 0; j < result.length && !found; ++j)
        {
            if (images[i] == result[j])
                found = true;
        }

        if (!found)
            result[result.length] = images[i];
    }

    return result;
}

var g_wsshImageResolver = new wsshImageResolver();